package cool.webstudy.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import cool.webstudy.admin.constant.enums.DelFlagEnum;
import cool.webstudy.admin.constant.enums.rescode.FileResCodeEnum;
import cool.webstudy.admin.exception.BusinessException;
import cool.webstudy.admin.mapper.file.FileRecordMapper;
import cool.webstudy.admin.model.dto.file.UpdateFileRecordDTO;
import cool.webstudy.admin.model.dto.user.UserDetailInfoDTO;
import cool.webstudy.admin.model.po.file.FileRecordPO;
import cool.webstudy.admin.model.vo.file.QueryFileRecordDetailInfoVO;
import cool.webstudy.admin.model.vo.file.UploadFileVO;
import cool.webstudy.admin.service.FileRecordService;
import cool.webstudy.admin.utils.UserDetailUtil;
import cool.webstudy.common.utils.UUIDUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * @author 莫振双
 * @date 2025/2/23 12:07
 * @description: 文件记录服务实现类
 */
@Service
public class FileRecordServiceImpl implements FileRecordService {
    @Autowired
    private FileRecordMapper fileRecordMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UploadFileVO uploadFile(MultipartFile file) {
        if (Objects.isNull(file)) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_FILE_MISS);
        }
        String unCode = UUIDUtil.getUUID();
        String filePath = saveFile(file, unCode);
        UserDetailInfoDTO userDetailInfoDTO = UserDetailUtil.getUserDetailInfo();
        FileRecordPO fileRecordPO = new FileRecordPO();
        fileRecordPO.setUnCode(unCode);
        fileRecordPO.setFileName(file.getOriginalFilename());
        fileRecordPO.setFilePath(filePath);
        fileRecordPO.setCreateBy(userDetailInfoDTO.getAccount());
        fileRecordPO.setCreateTime(new Date());
        fileRecordPO.setUpdateBy(userDetailInfoDTO.getAccount());
        fileRecordPO.setUpdateTime(new Date());
        fileRecordPO.setDelFlag(DelFlagEnum.NOT_DEL_FLAG.getFlag());
        try {
            fileRecordMapper.insert(fileRecordPO);
        } catch (Exception e) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_CREATE_FILE_RECORD);
        }
        UploadFileVO vo = new UploadFileVO();
        vo.setFileRecordUnCode(unCode);
        vo.setFilePath(filePath);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateFileRecord(UpdateFileRecordDTO dto) {
        if (Objects.isNull(dto) || StringUtils.isBlank(dto.getUnCode()) || StringUtils.isBlank(dto.getTableName()) || StringUtils.isBlank(dto.getTableUnCode()) || Objects.isNull(dto.getType())) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_UPDATE_FILE_PARAM_MISS);
        }
        UserDetailInfoDTO userDetailInfoDTO = UserDetailUtil.getUserDetailInfo();
        LambdaUpdateWrapper<FileRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(FileRecordPO::getUnCode, dto.getUnCode());
        updateWrapper.set(FileRecordPO::getTableName, dto.getTableName())
                .set(FileRecordPO::getTableUnCode, dto.getTableUnCode())
                .set(FileRecordPO::getType, dto.getType())
                .set(FileRecordPO::getUpdateBy, userDetailInfoDTO.getAccount())
                .set(FileRecordPO::getUpdateTime, new Date());
        try {
            fileRecordMapper.update(null, updateWrapper);
            return true;
        } catch (Exception e) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_UPDATE_FILE_RECORD);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFile(String unCode) {
        //暂时不需要
    }

    @Override
    public QueryFileRecordDetailInfoVO queryFileRecordDetailInfo(String unCode) {
        if (StringUtils.isBlank(unCode)) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_QUERY_FILE_PARAM_MISS);
        }
        LambdaQueryWrapper<FileRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileRecordPO::getUnCode, unCode);
        FileRecordPO fileRecordPO;
        try {
            fileRecordPO = fileRecordMapper.selectOne(queryWrapper);
            if (Objects.isNull(fileRecordPO)) {
                throw new BusinessException(FileResCodeEnum.RC_ERROR_QUERY_FILE_NOT_EXIST);
            }
            QueryFileRecordDetailInfoVO queryFileRecordDetailInfoVO = new QueryFileRecordDetailInfoVO();
            queryFileRecordDetailInfoVO.setUnCode(fileRecordPO.getUnCode());
            queryFileRecordDetailInfoVO.setFileName(fileRecordPO.getFileName());
            queryFileRecordDetailInfoVO.setFilePath(fileRecordPO.getFilePath());
            queryFileRecordDetailInfoVO.setTableName(fileRecordPO.getTableName());
            queryFileRecordDetailInfoVO.setTableUnCode(fileRecordPO.getTableUnCode());
            return queryFileRecordDetailInfoVO;
        } catch (Exception e) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_QUERY_FILE);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteFileRecord(String tableName, String tableUnCode) {
        if (StringUtils.isBlank(tableName) || StringUtils.isBlank(tableUnCode)){
            throw new BusinessException(FileResCodeEnum.RC_ERROR_DELETE_FILE_RECORD_PARAM_MISS);
        }
        UserDetailInfoDTO userDetailInfoDTO = UserDetailUtil.getUserDetailInfo();
        LambdaUpdateWrapper<FileRecordPO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(FileRecordPO::getTableName, tableName)
                .eq(FileRecordPO::getTableUnCode, tableUnCode)
                .set(FileRecordPO::getUpdateBy, userDetailInfoDTO.getAccount())
                .set(FileRecordPO::getUpdateTime, new Date())
                .set(FileRecordPO::getDelFlag, DelFlagEnum.DEL_FLAG.getFlag());
        try {
            fileRecordMapper.update(null, updateWrapper);
            return true;
        } catch (Exception e) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_DELETE_FILE_RECORD);
        }
    }

    @Override
    public Map<String, String> queryFileRecordAndTableUnCodeMap(String tableName) {
        if (StringUtils.isBlank(tableName)){
            throw new BusinessException(FileResCodeEnum.RC_ERROR_QUERY_FILE_RECORD_PARAM_MISS);
        }
        LambdaQueryWrapper<FileRecordPO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FileRecordPO::getTableName, tableName);
        try {
            List<FileRecordPO> fileRecordPOS = fileRecordMapper.selectList(queryWrapper);
            if (fileRecordPOS.isEmpty()){
                return new HashMap<>();
            }
            Map<String, String> map = new HashMap<>();
            for (FileRecordPO fileRecordPO : fileRecordPOS) {
                map.put(fileRecordPO.getTableUnCode(), fileRecordPO.getUnCode());
            }
            return map;
        } catch (Exception e) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_QUERY_FILE_LIST_RECORD);
        }
    }

    /**
     * @param file   文件对象
     * @param unCode 文件记录业务主键
     * @return String 文件存储的相对路径
     * @description: 将上传的文件保存到指定
     */
    private String saveFile(MultipartFile file, String unCode) {
        // 判断upload_files目录是否存在
        String filesDir = "./upload_files";
        Path path = Paths.get(filesDir);
        if (!Files.exists(path)) {
            // 目录不存在，创建目录
            try {
                Files.createDirectories(path);
            } catch (Exception e) {
                // 处理创建目录失败的异常
                throw new BusinessException(FileResCodeEnum.RC_ERROR_CREATE_DIR);
            }
        }
        String fileSuffix = getFileSuffix(file);
        // 处理文件
        String filePath = Paths.get(filesDir, unCode + fileSuffix).toString();
        try {
            //将文件写入磁盘中
            file.transferTo(Paths.get(filePath));
        } catch (Exception e) {
            // 处理文件保存失败的异常
            throw new BusinessException(FileResCodeEnum.RC_ERROR_CREATE_FILE);
        }
        return filePath;
    }

    //获取文件的后缀名
    private String getFileSuffix(MultipartFile file) {
        try {
            String originalFilename = file.getOriginalFilename();
            if (originalFilename != null) {
                int dotIndex = originalFilename.lastIndexOf(".");
                if (dotIndex > 0 && dotIndex < originalFilename.length() - 1) {
                    return "." + originalFilename.substring(dotIndex + 1);
                }
            }
            throw new BusinessException(FileResCodeEnum.RC_ERROR_GET_FILE_NAME);
        } catch (Exception e) {
            throw new BusinessException(FileResCodeEnum.RC_ERROR_GET_FILE_SUFFIX);
        }
    }
}
